package com.mengya.completablefuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName CompletableFutureDemo
 * @Description
 * @Author xiongwei.wu
 * @Date 2022/11/16 8:58
 **/
public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        join();
//        get();
//        getNow();
        complete();
    }

    /**
     * 使用异步编排，无自定义线程池时，需要手动延续线程关闭时间
     *
     * @throws InterruptedException
     */
    private static void m3() throws InterruptedException {
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 1;
        }).thenApply(f -> {
            return f + 100;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("----------result: " + v);
            }
        }).exceptionally(throwable -> {
            throwable.printStackTrace();
            return null;
        });


        System.out.println("--------main over");

        //使用CompletableFuture默认的线程池（ForkJoinPool）,需要延时等待子线程结束时间。否则当主线程结束后，默认会将起子线程全部结束
        TimeUnit.SECONDS.sleep(5);
    }

    /**
     * 使用异步编排  使用自定义线程池，不需要手动设置延时，自定义线程池会将该主线程及子线程全部执行完毕后shutdown()
     */
    private static void m4() {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,
                20,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(50),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        //异步编排
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 1;
        }, threadPoolExecutor).thenApply(f -> {
            return f + 2;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("-------result: " + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });

        System.out.println("main over");

        threadPoolExecutor.shutdown();
    }

    /**
     * 当get()阻塞时
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void m2() throws InterruptedException, ExecutionException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,
                20,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(50),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 11;
        });

        System.out.println(future3.get());

        System.out.println("----------main over");

        threadPoolExecutor.shutdown();
    }

    /**
     * CompletableFuture 4大函数
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void m1() throws InterruptedException, ExecutionException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,
                20,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(50),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
        });
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
        }, threadPoolExecutor);


        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
            return 11;
        });
        System.out.println(future3.get());

        CompletableFuture<Integer> future4 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "-------come in");
            return 12;
        }, threadPoolExecutor);
        System.out.println(future4.get());

        threadPoolExecutor.shutdown();
    }

    private static void join() {
        System.out.println(CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 2;
        }).thenApply(f -> {
            return f * 100;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("-----result:" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        }).join());
        System.out.println("-------main over");

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
    }

    private static void get() throws InterruptedException, ExecutionException {
        System.out.println(CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 2;
        }).thenApply(f -> {
            return f * 100;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("-----result:" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        }).get());
        System.out.println("-------main over");

        TimeUnit.SECONDS.sleep(3);
    }

    private static void getNow() throws InterruptedException {
        System.out.println(CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 2;
        }).thenApply(f -> {
            return f * 100;
        }).whenComplete((v, e) -> {
            if (e == null) {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException exception) {
                    exception.printStackTrace();
                }
                System.out.println("-----result:" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        }).getNow(99));
        System.out.println("-------main over");

        TimeUnit.SECONDS.sleep(3);
    }

    private static void complete() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
            return 2;
        }).thenApply(f -> {
            return f * 100;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("-----result:" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }

        System.out.println(future.complete(99) + " \t " + future.get());

        System.out.println("-------main over");

        TimeUnit.SECONDS.sleep(3);
    }
}
